/*******************************************************************************
 *                                    ZLG
 *                         ----------------------------
 *                         innovating embedded platform
 *
 * Copyright (c) 2001-present Guangzhou ZHIYUAN Electronics Co., Ltd.
 * All rights reserved.
 *
 * Contact information:
 * web site:    https://www.zlg.cn
 *******************************************************************************/
/*******************************************************************************
 * Includes
 ******************************************************************************/
#include "driver/usb/device/hpm6e00_usbd.h"

/*******************************************************************************
 * Static
 ******************************************************************************/
static struct usb_device_qh __g_usbd_qh[USB_DEVICE_QH_NUM] __attribute__((aligned(2048)))__attribute__((section(".dma_zone")));
static struct usb_device_td __g_usbd_td[USB_DEVICE_TD_NUM] __attribute__((aligned(64)))__attribute__((section(".dma_zone")));

/*******************************************************************************
 * Extern
 ******************************************************************************/
extern void l1c_dc_flush(uint32_t address, uint32_t size);
extern void l1c_dc_invalidate(uint32_t address, uint32_t size);

/*******************************************************************************
 * Code
 ******************************************************************************/
/**
 * \brief 传输描述分配
 */
static struct usb_device_td * __td_alloc(void){
    for (int i = 0; i < 64; i++) {
        if (__g_usbd_td[i].is_used == 0) {
            __g_usbd_td[i].is_used = 1;
            return &__g_usbd_td[i];
        }
    }
    return NULL;
}

/**
 * \brief 传输描述符释放
 */
static void __td_free(struct usb_device_td *p_td){
    memset(p_td, 0, sizeof(struct usb_device_td));
}

/**
 * \brief 传输描述符初始化
 */
static size_t __td_init(struct usb_device_td *p_td,
                        void                 *p_buf,
                        size_t                len,
                        uint16_t              mpk){
    uint32_t tmp, count;
    uint8_t  i;

    tmp = (uint32_t)p_buf;
    /* 初始化第一个缓存页指针*/
    p_td->buf[0] = tmp;

    /* 4K对齐*/
    count = 0x1000 - (tmp & 0x0fff);

    if (len <= count) {
        count = len;
    } else {
        /* 下一个4K对齐的地址*/
        tmp +=  0x1000;
        tmp &= ~0x0fff;

        /* 初始化下一个缓存页指针*/
        for (i = 1; (count < len) && (i < 5); i++) {

            p_td->buf[i] = tmp;

            tmp += 0x1000;

            if ((count + 0x1000) < len) {
                count += 0x1000;
            } else {
                count = len;
            }
        }
        /* todo 待修改 */
        if (count != len) {
            count -= (count % mpk);
        }
    }

    /* 填充传输大小，设置激活位*/
    tmp = ((count << USBD_DTD_TOTAL_BYTES_POS) | USBD_DTD_STA_ACTIVE_MASK);

    p_td->next      = 1u;
    p_td->p_td_next = NULL;
    p_td->p_td_priv = NULL;
    p_td->token     = tmp;
    p_td->len       = count;

    return count;
}

int usb_device_bus_reset(hpm_usb_reg_t *p_usb_reg){
    uint32_t time_out = 5000;
    /* The reset value for all endpoint types is the control endpoint. If one endpoint
     * direction is enabled and the paired endpoint of opposite direction is disabled, then the
     * endpoint type of the unused direction must be changed from the control type to any other
     * type (e.g. bulk). Leaving an un-configured endpoint control will cause undefined behavior
     * for the data PID tracking on the active endpoint.
     */

    for(int i = 1; i < 8; i++) {
        WRITE_REG32(p_usb_reg->endptctrl[i], (USB_EP_TYPE_BULK << USB_ENDPTCTRL_TXT_POS) | (USB_EP_TYPE_BULK << USB_ENDPTCTRL_RXT_POS));
    }

    /* 清除所有寄存器 */
    WRITE_REG32(p_usb_reg->endpt_nak, READ_REG32(p_usb_reg->endpt_nak));
    WRITE_REG32(p_usb_reg->endpt_nak_en, 0);
    WRITE_REG32(p_usb_reg->usb_sts, READ_REG32(p_usb_reg->usb_sts));
    WRITE_REG32(p_usb_reg->endptsetupstat, READ_REG32(p_usb_reg->endptsetupstat));
    WRITE_REG32(p_usb_reg->endptcomplete, READ_REG32(p_usb_reg->endptcomplete));

    while ((--time_out) && (READ_REG32(p_usb_reg->endpointprime)));
    if (time_out == 0) {
        return -ETIME;
    }

    WRITE_REG32(p_usb_reg->endptflush, 0xFFFFFFFF);

    time_out = 5000;
    while ((--time_out) && (READ_REG32(p_usb_reg->endptflush)));
    if (time_out == 0) {
        return -ETIME;
    }

    return 0;
}

/**
 * \brief USB 设备控制器初始化
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 *
 * \retval 成功返回 0
 */
int usb_device_init(hpm_usb_reg_t *p_usb_reg){
    int      ret;
    uint32_t dcc_params, tmp;
    uint32_t time_out = 5000;

    ret = usb_reg_chk(p_usb_reg);
    if (ret != 0) {
        return ret;
    }

    /* 初始化 PHY */
    ret = usb_phy_init(HPM_USB0);
    if (ret != 0) {
        return ret;
    }

    memset(&__g_usbd_qh, 0, sizeof(struct usb_device_qh) * USB_DEVICE_QH_NUM);
    memset(&__g_usbd_td, 0, sizeof(struct usb_device_td) * USB_DEVICE_TD_NUM);

    dcc_params = READ_REG32(p_usb_reg->dcc_params);
    if (!(dcc_params & USB_DCCPARAMS_DC_MASK)) {
        return -ENOTSUP;
    }

    /* 停止 USB 控制器 */
    tmp = READ_REG32(p_usb_reg->usb_cmd);
    tmp &= ~USB_USBCMD_RS_MASK;
    WRITE_REG32(p_usb_reg->usb_cmd, tmp);
    /* 复位 USB 控制器 */
    tmp = READ_REG32(p_usb_reg->usb_cmd);
    tmp |= USB_USBCMD_RST_MASK;
    WRITE_REG32(p_usb_reg->usb_cmd, tmp);
    /* 等待复位完成 */
    while ((--time_out) && (READ_REG32(p_usb_reg->usb_cmd) & USB_USBCMD_RST_MASK));
    if (time_out == 0) {
        return -ETIME;
    }

    /* 设置控制器为设备控制器 */
    tmp = READ_REG32(p_usb_reg->usbmode);
    tmp &= ~USB_USBMODE_CM_MASK;
    tmp |= USB_USBMODE_CTRL_MODE_DEVICE;
    /* 启动 SETUP 锁定 */
    tmp &= ~USB_USBMODE_SLOM_MASK;
    /* 设置为小端模式 */
    tmp &= ~USB_USBMODE_ES_MASK;
    WRITE_REG32(p_usb_reg->usbmode, tmp);

    tmp = READ_REG32(p_usb_reg->usb_cmd);
    tmp &= ~USB_USBCMD_ITC_MASK;
    tmp |= (USB_ITC_8_MICRO_FRAME << USB_USBCMD_ITC_POS);
    WRITE_REG32(p_usb_reg->usb_cmd, tmp);

    tmp = READ_REG32(p_usb_reg->portsc1);
    /* 设置平行接口信号 */
    tmp &= ~USB_PORTSC1_STS_MASK;
    /* 设置 8 位 UTMI 接口 */
    tmp &= ~USB_PORTSC1_PTW_MASK;
    WRITE_REG32(p_usb_reg->portsc1, tmp);

    /* 关闭所有中断*/
    WRITE_REG32(p_usb_reg->usb_intr, 0);
    /* 清除 USB 状态*/
    WRITE_REG32(p_usb_reg->usb_sts, 0);
    /* 设置端点链表地址 */
    tmp = (uint32_t)(__g_usbd_qh);
    tmp &= USB_ENDPTLISRADDR_EPBASE_MASK;
    WRITE_REG32(p_usb_reg->endpoint_list_addr, tmp);

    /* Enable VBUS discharge */
    SET_REG32_BIT(p_usb_reg->otgsc, USB_OTGSC_VD_MASK);

    return 0;
}

/**
 * \brief USB 设备控制器反初始化
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 *
 * \retval 成功返回 0
 */
int usb_device_deinit(hpm_usb_reg_t *p_usb_reg){
    uint32_t tmp;
    uint32_t time_out = 5000;

    tmp = READ_REG32(p_usb_reg->usb_cmd);
    tmp &= ~USB_USBCMD_RS_MASK;
    tmp |= USB_USBCMD_RST_MASK;
    WRITE_REG32(p_usb_reg->usb_cmd, tmp);
    /* 等待复位完成 */
    while ((--time_out) && (READ_REG32(p_usb_reg->usb_cmd) & USB_USBCMD_RST_MASK));
    if (time_out == 0) {
        return -ETIME;
    }

    usb_phy_deinit(HPM_USB0);

    WRITE_REG32(p_usb_reg->endpoint_list_addr, 0);
    WRITE_REG32(p_usb_reg->usb_sts, READ_REG32(p_usb_reg->usb_sts));
    WRITE_REG32(p_usb_reg->usb_intr, 0);

    return 0;
}

/**
 * \brief USB 设备控制器启动
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 *
 * \retval 成功返回 0
 */
int usb_device_start(hpm_usb_reg_t *p_usb_reg){
    uint32_t tmp;
    int      ret;

    ret = usb_reg_chk(p_usb_reg);
    if (ret != 0) {
        return ret;
    }
    /* 使能设备控制器中断 */
    tmp = USB_USBINTR_UE_MASK | USB_USBINTR_UEE_MASK
        | USB_USBINTR_PCE_MASK | USB_USBINTR_URE_MASK
        | USB_USBINTR_SLE_MASK | USB_USBINTR_SEE_MASK;

    WRITE_REG32(p_usb_reg->usb_intr, tmp);
    WRITE_REG32(p_usb_reg->usb_sts, tmp);

    /* 设置控制器为设备模式 */
    tmp = READ_REG32(p_usb_reg->usbmode);
    tmp &= ~USB_USBMODE_CM_MASK;
    tmp |= USB_USBMODE_CTRL_MODE_DEVICE;
    WRITE_REG32(p_usb_reg->usbmode, tmp);

    /* 设置控制器运行 */
    tmp = READ_REG32(p_usb_reg->usb_cmd);
    tmp |= USB_USBCMD_RS_MASK;
    WRITE_REG32(p_usb_reg->usb_cmd, tmp);

    return 0;
}

/**
 * \brief USB 设备控制器停止函数
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 *
 * \retval 成功返回 0
 */
int usb_device_stop(hpm_usb_reg_t *p_usb_reg){
    uint32_t tmp, time_out = 5000;;
    int      ret;

    ret = usb_reg_chk(p_usb_reg);
    if (ret != 0) {
        return ret;
    }

    tmp = READ_REG32(p_usb_reg->usb_cmd);
    tmp &= ~USB_USBCMD_RS_MASK;
    tmp |= USB_USBCMD_RS_MASK;
    WRITE_REG32(p_usb_reg->usb_cmd, tmp);

    SET_REG32_BIT(p_usb_reg->usb_sts, USB_USBSTS_SRI_MASK);

    while ((--time_out) && (!(READ_REG32(p_usb_reg->usb_sts) & USB_USBSTS_SRI_MASK)));
    if (time_out == 0) {
        return -ETIME;
    }

    tmp = READ_REG32(p_usb_reg->usb_cmd);
    tmp &= ~USB_USBCMD_RS_MASK;
    WRITE_REG32(p_usb_reg->usb_cmd, tmp);

    return 0;
}

/**
 * \brief USB 设备控制器设置地址
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 * \param[in] addr      要设置的地址
 *
 * \retval 成功返回 0
 */
int usb_device_addr_set(hpm_usb_reg_t *p_usb_reg, uint8_t addr){
    int      ret;

    ret = usb_reg_chk(p_usb_reg);
    if (ret != 0) {
        return ret;
    }
    WRITE_REG32(p_usb_reg->device_addr,
               (addr << USB_DEVICEADDR_ADR_POS) | (USB_DEVICEADDR_ADRA_MASK));

    return 0;
}

/**
 * \brief USB 设备控制器端点初始化
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 * \param[in] ep_addr   端点地址
 * \param[in] ep_type   端点类型
 *
 * \retval 成功返回 0
 */
int usb_device_ep_init(hpm_usb_reg_t *p_usb_reg,
                       uint8_t        ep_addr,
                       uint8_t        ep_type){
    uint32_t ep_ctrl = 0;
    int      ret;

    ret = usb_reg_chk(p_usb_reg);
    if (ret != 0) {
        return ret;
    }
    ep_ctrl = READ_REG32(p_usb_reg->endptctrl[ep_addr & 0x0F]);

    if (ep_addr & 0x80) {
        if (ep_addr & 0x0F) {
            ep_ctrl |= USB_ENDPTCTRL_TXR_MASK;
        }
        /* 使能发送传输*/
        ep_ctrl |= USB_ENDPTCTRL_TXE_MASK;
        ep_ctrl |= ((uint32_t)(ep_type) << USB_ENDPTCTRL_TXT_POS);
    } else {
        if (ep_addr & 0x0F) {
            /* 不是端点0*/
            ep_ctrl |= USB_ENDPTCTRL_RXR_MASK;
        }
        /* 使能接收传输*/
        ep_ctrl |= USB_ENDPTCTRL_RXE_MASK;
        ep_ctrl |= ((uint32_t)(ep_type) << USB_ENDPTCTRL_RXT_POS);
    }

    WRITE_REG32(p_usb_reg->endptctrl[ep_addr & 0x0F], ep_ctrl);

    return 0;
}

/**
 * \brief USB 设备控制器端点使能
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 * \param[in] ep_addr   端点地址
 *
 * \retval 成功返回 0
 */
int usb_device_ep_enable(hpm_usb_reg_t *p_usb_reg, uint8_t ep_addr){
    uint32_t ep_ctrl;
    int      ret;

    ret = usb_reg_chk(p_usb_reg);
    if (ret != 0) {
        return ret;
    }

    ep_ctrl = READ_REG32(p_usb_reg->endptctrl[ep_addr & 0x0F]);
    if (ep_addr & 0x80) {
        ep_ctrl |= USB_ENDPTCTRL_TXE_MASK;
    } else {
        ep_ctrl |= USB_ENDPTCTRL_RXE_MASK;
    }
    WRITE_REG32(p_usb_reg->endptctrl[ep_addr & 0x0F], ep_ctrl);

    return 0;
}

/**
 * \brief USB 设备控制器端点禁能
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 * \param[in] ep_addr   端点地址
 *
 * \retval 成功返回 0
 */
int usb_device_ep_disable(hpm_usb_reg_t *p_usb_reg, uint8_t ep_addr){
    uint32_t ep_ctrl;
    int      ret;

    ret = usb_reg_chk(p_usb_reg);
    if (ret != 0) {
        return ret;
    }

    ep_ctrl = READ_REG32(p_usb_reg->endptctrl[ep_addr & 0x0F]);
    if (ep_addr & 0x80) {
        ep_ctrl &= ~USB_ENDPTCTRL_TXE_MASK;
    } else {
        ep_ctrl &= ~USB_ENDPTCTRL_RXE_MASK;
    }
    WRITE_REG32(p_usb_reg->endptctrl[ep_addr & 0x0F], ep_ctrl);

    return 0;
}

/**
 * \brief USB 设备控制器端点停止设置
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 * \param[in] ep_addr   端点地址
 * \param[in] is_set    是否停止
 *
 * \retval 成功返回 0
 */
int usb_device_ep_halt_set(hpm_usb_reg_t *p_usb_reg, uint8_t ep_addr, bool_t is_set){
    int                   ret;
    uint32_t              ep_ctrl = 0;
    uint8_t               dir, ep_num;
    struct usb_device_qh *p_qh = NULL;

    ret = usb_reg_chk(p_usb_reg);
    if (ret != 0) {
        return ret;
    }

    dir    = ep_addr & 0x80;
    ep_num = ep_addr & 0x0f;

    p_qh = usb_device_qh_get(ep_addr);
    if (p_qh == NULL) {
        return -EINVAL;
    }
    /* 如果有任何传输请求在队列里，停止端点会失败*/
    if ((is_set == TRUE) && (dir == 0x80) && (p_qh->p_td_list)) {
        return -EAGAIN;
    }

    ep_ctrl = READ_REG32(p_usb_reg->endptctrl[ep_num]);

    if (is_set == TRUE) {
        if (ep_num == 0) {
            ep_ctrl |= (USB_ENDPTCTRL_TXS_MASK | USB_ENDPTCTRL_RXS_MASK);
        }
        /* 设置停止位*/
        else if (dir == 0x80) {
            ep_ctrl |= USB_ENDPTCTRL_TXS_MASK;
        } else {
            ep_ctrl |= USB_ENDPTCTRL_RXS_MASK;
        }
    } else {
        /* 清除停止位和复位数据翻转*/
        if (dir == 0x80) {
            ep_ctrl &= ~USB_ENDPTCTRL_TXS_MASK;
            ep_ctrl |= USB_ENDPTCTRL_TXR_MASK;
        } else {
            ep_ctrl &= ~USB_ENDPTCTRL_RXS_MASK;
            ep_ctrl |= USB_ENDPTCTRL_RXR_MASK;
        }
    }
    WRITE_REG32(p_usb_reg->endptctrl[ep_num], ep_ctrl);

    return 0;
}

/**
 * \brief USB 设备控制器端点 FIFO 冲刷
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 * \param[in] ep_addr   要冲刷的端点地址
 *
 * \retval 成功返回 0
 */
int usb_device_ep_fifo_flush(hpm_usb_reg_t *p_usb_reg, uint8_t ep_addr){
    uint32_t bits, time_out = 5000;
    int      ret = -EINVAL;

    ret = usb_reg_chk(p_usb_reg);
    if (ret != 0) {
        return ret;
    }

    if (ep_addr & 0x80) {
        bits = 1 << (16 + (ep_addr & 0x0F));
    } else {
        bits = 1 << (ep_addr & 0x0F);
    }

//    if (!(READ_REG32(p_usb_reg->endptstatus) & bits)) {
//        return 0;
//    }

    do {
        WRITE_REG32(p_usb_reg->endptflush, bits);

        /* 等待冲刷完成 */
        while ((--time_out) && READ_REG32(p_usb_reg->endptflush));
        if (time_out == 0) {
            return -ETIME;
        }

    /* 检查是否要再次冲刷 FIFO */
    } while ((READ_REG32(p_usb_reg->endptstatus) & bits));

    return 0;
}

/**
 * \brief 端点传输描述符扫描函数
 *
 * \param[in] p_usb_reg 相关的 USB 寄存器
 * \param[in] ep_addr   要扫描的端点地址
 *
 * \retval 成功返回 0
 */
int usb_device_ep_td_scan(hpm_usb_reg_t *p_usb_reg, uint8_t ep_addr){
    struct usb_device_td *p_td, *p_prev_td = NULL;
    struct usb_device_qh *p_qh             = NULL;
    uint32_t              token, temp;
    uint32_t              len_act          = 0;
    uint16_t              remain_len;
    int                   ret, status      = 0;

    ret = usb_reg_chk(p_usb_reg);
    if (ret != 0) {
        return ret;
    }

    p_qh = usb_device_qh_get(ep_addr);
    if (p_qh == NULL) {
        return -EINVAL;
    }
    if (p_qh->is_init != TRUE) {
        return -EPERM;
    }
    p_td = p_qh->p_td_list;

    while (p_td != NULL) {
        if (p_prev_td) {
            if (p_prev_td->p_fn_done) {
                if ((p_prev_td->p_buf != NULL) && ((ep_addr & 0x80) == 0)) {
                    l1c_dc_invalidate((uint32_t)p_prev_td->p_buf, len_act);
                }

                /* 传输的最后一个传输描述符，调用完成回调*/
                p_prev_td->p_fn_done(p_prev_td->p_arg, status, len_act);

                if (status != 0) {
                    /* 清除错误和停止的问题*/
                    temp = p_qh->info2;
                    temp &= ~(USBD_DTD_STA_HALTED_MASK |
                              USBD_DTD_STA_DATA_BUFF_ERR_MASK |
                              USBD_DTD_STA_TRANSACTION_ERR_MASK);
                    p_qh->info2 = temp;
                    status = 0;
                }
            }
            /* 释放传输描述符*/
            __td_free(p_prev_td);

            p_prev_td = NULL;
        }
        /* 检查传输描述符的状态*/
        if (status == 0) {
            token      = p_td->token;
            remain_len = USBD_DTD_TOTAL_BYTES(token);

            if (token & USBD_DTD_STA_HALTED_MASK) {
                /* 停止*/
                status = -EPIPE;
            } else if (token & USBD_DTD_STA_DATA_BUFF_ERR_MASK) {
                /* 缓存错误*/
                status = -EPROTO;
            } else if (token & USBD_DTD_STA_TRANSACTION_ERR_MASK) {
                /* 传输错误*/
                status = -EILSEQ;
            } else if (token & USBD_DTD_STA_ACTIVE_MASK){
                /* 传输正在进行中，继续下一个传输描述符*/
                p_td = p_td->p_td_next;
                continue;
            } else if (remain_len) {
                /* 还有一些数据还没有传输*/
                status = 0;
            } else {
                /* 传输完成*/
                status = 0;
            }

            if (status == 0) {
                len_act += (p_td->len - remain_len);
            }
        }

        p_prev_td = p_td;
        p_td      = p_td->p_td_next;

        if (p_prev_td->p_td_priv != NULL) {
            p_prev_td->p_td_priv->next      = p_prev_td->next;
            p_prev_td->p_td_priv->p_td_next = p_prev_td->p_td_next;
        } else {
            p_qh->p_td_list = p_prev_td->p_td_next;
        }
        if (p_prev_td->p_td_next != NULL) {
            p_prev_td->p_td_next->p_td_priv = p_prev_td->p_td_priv;
        }
        p_prev_td->p_td_priv = NULL;
        p_prev_td->p_td_next = NULL;
    }
    /* 最后一个传输描述符*/
    if (p_prev_td) {

        if ((p_prev_td->p_buf != NULL) && ((ep_addr & 0x80) == 0)) {
            l1c_dc_invalidate((uint32_t)p_prev_td->p_buf, len_act);
        }

        if (p_prev_td->p_fn_done) {
            p_prev_td->p_fn_done(p_prev_td->p_arg, status, len_act);
        }
        __td_free(p_prev_td);

        p_prev_td = NULL;
    }
    return 0;
}

/**
 * \brief 队列头初始化
 */
int usb_device_qh_init(uint8_t  ep_addr,
                       uint8_t  ep_type,
                       uint16_t mpk,
                       bool_t   zlt,
                       uint8_t  mult){
    uint32_t tmp;
    uint8_t  idx;

    idx = (ep_addr & 0x07) * 2;

    if (ep_addr & 0x80) {
        idx = 1 + idx;
    }
    tmp = (mpk << USBD_DQH_MAX_PKT_POS);

    /* 设置队列头的端点性能*/
    switch (ep_type) {
        case USB_EP_TYPE_CTRL:
            /* 控制端点，设置中断 Interrupt On Setup (IOS) */
            tmp |= USBD_DQH_ISO_MASK;
            break;
        case USB_EP_TYPE_ISO:
            tmp |= (mult << USBD_DQH_MULT_POS);
            break;
        case USB_EP_TYPE_BULK:
        case USB_EP_TYPE_INT:
            break;
        default:
            return -EINVAL;
    }
    if (zlt) {
        tmp |= USBD_DQH_ZLT_MASK;
    }

    __g_usbd_qh[idx].info1    = tmp;
    __g_usbd_qh[idx].next_dtd = 1u;
    __g_usbd_qh[idx].info2    = 0;
    __g_usbd_qh[idx].is_init  = TRUE;

    return 0;
}

/**
 * \brief 队列头获取
 *
 * \param[in] ep_addr 端点地址
 *
 * \retval 成功返回 USB 设备控制器队列头
 */
struct usb_device_qh *usb_device_qh_get(uint8_t ep_addr){
    uint8_t idx = ep_addr & 0x07;

    idx = idx * 2;

    if (ep_addr & 0x80) {
        idx = idx + 1;
    }
    return &__g_usbd_qh[idx];
}

/**
 * \brief USB 设备控制器传输描述符链表制作
 *
 * \param[in] mpk       最大包大小
 * \param[in] p_buf     缓存
 * \param[in] len       缓存大小
 * \param[in] p_fn_done 传输完成回调函数
 * \param[in] p_arg     传输完成回调函数参数
 *
 * \retval 成功返回 传输描述符链表
 */
struct usb_device_td *usb_device_td_list_make(uint16_t         mpk,
                                              uint8_t         *p_buf,
                                              uint32_t         len,
                                              p_fn_trans_done  p_fn_done,
                                              void            *p_arg){
    struct usb_device_td *p_td       = NULL;
    struct usb_device_td *p_td_first = NULL;
    struct usb_device_td *p_td_prev  = NULL;
    uint32_t              tmp;
    uint8_t              *p_tmp      = NULL;

    if (len) {
        l1c_dc_flush((uint32_t)p_buf, len);
        p_tmp = p_buf;
    }

    do {
        /* 分配传输描述符*/
        p_td = __td_alloc();
        if (p_td == NULL) {
            goto __failed;
        }

        /* 初始化传输描述符*/
        tmp = __td_init(p_td, p_tmp, len, mpk);

        len    -= tmp;
        p_tmp  += tmp;

        if (p_td_prev) {
            /* 链接下一个传输描述符*/
            p_td_prev->next      = (uint32_t)p_td;
            p_td_prev->p_td_next = p_td;
            p_td->p_td_priv      = p_td_prev;
        }
        if (p_td_first == NULL) {
            p_td_first = p_td;
        }
        p_td_prev   = p_td;
        p_td->p_buf = p_buf;
    } while (len);

    /* 最后一个传输描述符使能中断 */
    p_td->token     = p_td->token | USBD_DTD_IOC_MASK;
    p_td->p_fn_done = p_fn_done;
    p_td->p_arg     = p_arg;

    return p_td_first;

__failed:
    if (p_td_first != NULL) {
        p_td = p_td_first;

        do {
            p_td_prev = p_td;
            p_td      = p_td_prev->p_td_next;

            __td_free(p_td_prev);
        } while (p_td);
    }
    return NULL;
}

/**
 * \brief USB 设备控制器传输描述符插入
 *
 * \param[in] p_usb_reg 相关 USB 寄存器
 * \param[in] ep_addr   端点地址
 * \param[in] p_td      传输描述符链表
 *
 * \retval 成功返回 0
 */
int usb_device_ep_td_insert(hpm_usb_reg_t        *p_usb_reg,
                            uint8_t               ep_addr,
                            struct usb_device_td *p_td){
    uint32_t              bitmask, tmp, ep_status;
    uint8_t               ep_num;
    struct usb_device_qh *p_qh = NULL;
    int                   ret;

    ret = usb_reg_chk(p_usb_reg);
    if (ret != 0) {
        return ret;
    }

    p_qh = usb_device_qh_get(ep_addr);
    if (p_qh == NULL) {
        return -EINVAL;
    }
    if (p_qh->is_init != TRUE) {
        return -EAGAIN;
    }

    ep_num  = ep_addr & 0x0F;
    bitmask = (ep_addr & 0x80) ? (1 << (ep_num + 16)) : (1 << (ep_num));

    if (p_qh->p_td_list != NULL) {
        struct usb_device_td *p_tail_td = p_qh->p_td_list;

        while (p_tail_td->p_td_next != NULL) {
            p_tail_td = p_tail_td->p_td_next;
        }

        p_tail_td->p_td_next = p_td;
        /* 链接两个传输描述符链表*/
        p_tail_td->next = ((uint32_t)p_td & USBD_DTD_ADDR_MASK);

        /* 读取端点 Prime 位，检查端点是否还有一些旧的传输描述符在传输*/
        if (READ_REG32(p_usb_reg->endpointprime) & bitmask) {
            return 0;
        }

        do {
            /* 设置 ATDTW 位，告诉控制器有新的传输描述符*/
            tmp = READ_REG32(p_usb_reg->usb_cmd);
            WRITE_REG32(p_usb_reg->usb_cmd, (tmp | USB_USBCMD_ATDTW_MASK));

            /* 读取当前的状态位*/
            ep_status = READ_REG32(p_usb_reg->endptstatus) & bitmask;

        } while (!(READ_REG32(p_usb_reg->usb_cmd) & USB_USBCMD_ATDTW_MASK));

        /* 清除 ATDTW 位*/
        tmp = READ_REG32(p_usb_reg->usb_cmd);
        WRITE_REG32(p_usb_reg->usb_cmd, (tmp & ~USB_USBCMD_ATDTW_MASK));

        /* 如果端点还在传输，检查端点状态*/
        if (ep_status) {
            return 0;
        }
    } else {
        p_qh->p_td_list = p_td;
    }

    /* Write dQH next pointer and terminate bit to 0 */
    tmp = (uint32_t)p_td & USBD_DTD_ADDR_MASK;

    p_qh->next_dtd = tmp;

    /* 清除启动位和停止位*/
    tmp = ~(USBD_DQH_STA_ACTIVE_MASK | USBD_DQH_STA_HALT_MASK);
    p_qh->info2 &= tmp;

    /* ENDPTPRIME 寄存器对应的端点位写 1 开始传输*/
    WRITE_REG32(p_usb_reg->endpointprime, bitmask);

    return 0;
}

/**
 * \brief USB 设备控制器传输描述符移除
 *
 * \param[in] p_usb_reg 相关 USB 寄存器
 * \param[in] ep_addr   端点地址
 * \param[in] p_buf     传输描述符相关的缓存地址
 *
 * \retval 成功返回 0
 */
int usb_device_td_list_remove(hpm_usb_reg_t *p_usb_reg,
                              uint8_t        ep_addr,
                              uint8_t       *p_buf){
    int                   ret       = 0;
    uint32_t              tmp;
    struct usb_device_qh *p_qh      = NULL;
    struct usb_device_td *p_td      = NULL;
    struct usb_device_td *p_td_priv = NULL;

    ret = usb_reg_chk(p_usb_reg);
    if ((ret != 0) || (p_buf == NULL)) {
        return -EINVAL;
    }
    p_qh = usb_device_qh_get(ep_addr);
    if (p_qh == NULL) {
        return -EINVAL;
    }
    if (p_qh->is_init != TRUE) {
        return -EAGAIN;
    }
    p_td = p_qh->p_td_list;

    usb_device_ep_disable(p_usb_reg, ep_addr);

    while (p_td != NULL) {
        p_td_priv = p_td;
        p_td      = p_td->p_td_next;

        if (p_td_priv->p_buf == p_buf) {
            if (p_td_priv->p_td_priv != NULL) {
                p_td_priv->p_td_priv->next      = p_td_priv->next;
                p_td_priv->p_td_priv->p_td_next = p_td_priv->p_td_next;
            } else {
                p_qh->p_td_list = p_td_priv->p_td_next;
                p_qh->curr_dtd  = 0;

                if (p_td_priv->p_td_next) {
                    p_qh->next_dtd  = (uint32_t)(p_td_priv->p_td_next);
                }
            }
            if (p_td_priv->p_td_next != NULL) {
                p_td_priv->p_td_next->p_td_priv = p_td_priv->p_td_priv;
            }
            p_td_priv->p_td_priv = NULL;
            p_td_priv->p_td_next = NULL;

            if (p_td_priv->p_fn_done) {
                p_td_priv->p_fn_done(p_td_priv->p_arg, -EPERM, 0);
            }
            __td_free(p_td_priv);
        }
    }

    /* 清除启动位和停止位*/
    tmp = ~(USBD_DQH_STA_ACTIVE_MASK | USBD_DQH_STA_HALT_MASK);
    p_qh->info2 &= tmp;

    /* 使能端点*/
    usb_device_ep_enable(p_usb_reg, ep_addr);

    return ret;
}

